#!/bin/bash

# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# Simple wrapper script to build the chromeos-chrome package incrementally.

. /usr/lib/crosutils/common.sh || exit 1

DEFINE_string board "${DEFAULT_BOARD}" \
    "Board for which to build the package."
DEFINE_boolean runhooks "${FLAGS_FALSE}" \
    "Re-run hooks contained in the DEPS file - i.e., regenerate Makefiles."
DEFINE_boolean build_tests "${FLAGS_FALSE}" \
    "Build test targets."
DEFINE_boolean ccache "${FLAGS_FALSE}" \
    "Compile with ccache."
DEFINE_boolean install "${FLAGS_FALSE}" \
    "Install to a temporary directory."

# Parse command line.
FLAGS "$@" || exit 1
eval set -- "${FLAGS_ARGV}"

if [ $# -ne 0 ]; then
  CHROME_TARGET_OVERRIDE="$*"
  echo "Custom build targets specified: ${CHROME_TARGET_OVERRIDE}"
fi

if [ -z "${FLAGS_board}" ]; then
  die "You must specify --board="
fi

if [ -n "${FLAGS_board}" ]; then
  BOARD_DIR=/build/"${FLAGS_board}"
  EBUILDCMD=ebuild-"${FLAGS_board}"
  EMERGECMD=emerge-"${FLAGS_board}"
  EQUERYCMD=equery-"${FLAGS_board}"
  BOARD_STR="${FLAGS_board}"
  BOARD_KEYWORD="$(portageq-${FLAGS_board} envvar ARCH)"
fi

chrome_workon="chromeos-base/chromeos-chrome"
chrome="chromeos-chrome"
unstable_suffix="9999"
workon_name="${chrome}-${unstable_suffix}"
cache_dir="/build/${BOARD_STR}/tmp/cros_chrome_make"
useflags_file="${cache_dir}/PREV_USEFLAGS"
src_hash_file="${cache_dir}/PREV_SRC_HASH"
gerrit_chrome_root="/home/$(whoami)/trunk/chromium"
gerrit_chrome_src="${gerrit_chrome_root}/src"
pkgfile=
workpath=

cros_workon_list() {
  # Get list of packages being cros-worked on.
  cros_workon --board="${FLAGS_board}" list
}

get_upstream_base_hash() {
  # Get the upstream change that the local changes in the repo is based on.
  # This gets updated on a rebase (happens during repo sync).
  echo $(cd ${gerrit_chrome_src}; git merge-base m/master HEAD)
}

get_prev_useflags() {
  # Get the user-specified USE flags from the last run
  if [ -e ${useflags_file} ]; then
    cat ${useflags_file}
  fi
}

get_prev_src_hash() {
  # Get the upstream hash that the local changes were based on the last time
  # hooks were run.
  if [ -e ${src_hash_file} ]; then
    cat ${src_hash_file}
  fi
}

was_last_run_local_src() {
  # Checks the symlink to CHROME_ROOT in the working dir to see if the last run
  # was done with CHROME_ORIGIN=LOCAL_SOURCE
  if [ ! -e "${workpath}/work/${workon_name}" ]; then
    return 1   # False
  else
    return 0   # True
  fi
}

decide_use_flags() {
  # Do not set 'runhooks' useflag here because we don't want to consider it
  # when comparing use flags between runs.
  if [ "${FLAGS_build_tests}" = "${FLAGS_FALSE}" ]; then
    echo "${USE} -build_tests"
  else
    echo "${USE} build_tests"
  fi
}

decide_auto_runhooks_local_src() {
  # Decide whether to run 'gclient runhooks' for LOCAL_SOURCE.
  # We rerun hooks when user-specified useflags change.
  local _runhooks=0   # True
  if [ -e "${workpath}/.prepared" ] && was_last_run_local_src && \
     [ "$(get_prev_useflags)" = "$(decide_use_flags)" ]; then
    _runhooks=1   # False
  fi

  return ${_runhooks}
}

# Make temporary cache directory
#
# We keep three pieces of information in the temp directory:
# 1. The useflags set by the user on the last run.
# 2. In the case of CHROME_ORIGIN==LOCAL_SOURCE, The git hash of the upstream
#    change chromium/src is based on.  A change in the git hash alerts us to a
#    'repo sync' that was run, in which case we need to re-run hooks.
if [ ! -e ${cache_dir} ]; then
  mkdir ${cache_dir}
fi

# Find the ebuild file.
if ! pkgfile=$(ACCEPT_KEYWORDS="~${BOARD_KEYWORD}" "${EQUERYCMD}" which \
   "${workon_name}" 2> /dev/null); then
  die "error looking up ${chrome}"
fi

# Find the portage work directory for this package.
workpath="/build/${BOARD_STR}/tmp/portage/$( \
          echo "${pkgfile}" | \
            awk -F '/' '{ print $(NF-2) "/" $(NF-1) }')-${unstable_suffix}"

use="$(decide_use_flags)"

: ${CHROME_ORIGIN:=LOCAL_SOURCE}

if [ "${CHROME_ORIGIN}" = "LOCAL_SOURCE" ]; then
  auto_runhooks=decide_auto_runhooks_local_src
fi

# Changing the ccache flag should not trigger a 'gclient runhooks', so
# do not save its state between runs.
ccache="-ccache"
if [ "${FLAGS_ccache}" = "${FLAGS_TRUE}" ]; then
  ccache="ccache"
fi

runhooks="-runhooks"
if [ "${FLAGS_runhooks}" = "${FLAGS_TRUE}" ] || ${auto_runhooks}; then
  runhooks="runhooks"
fi

# TODO(rcui): crosbug.com/20435.  Investigate not running 'clean' and just
# re-running the compile stage when the Chrome build switches to Ninja inside
# the chroot.
ebuild_actions="clean"
if [ "${FLAGS_install}" = "${FLAGS_FALSE}" ]; then
  ebuild_actions="${ebuild_actions} compile"
else
  ebuild_actions="${ebuild_actions} install"
fi

eval "USE='${use} -verbose ${runhooks}'" CCACHE_SIZE=2G \
     "FEATURES='${FEATURES} ${ccache}'" "CHROME_ORIGIN='${CHROME_ORIGIN}'" \
     "CHROME_TARGET_OVERRIDE='${CHROME_TARGET_OVERRIDE}'" \
     "${EBUILDCMD}" "${pkgfile}" "${ebuild_actions}" \
     || die "Failed to execute the ebuild."

# If we didn't get to run hooks, don't update our cache.
if [ -e "${workpath}/.prepared" ]; then
  echo "${use}" > ${useflags_file}
fi
